/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shmallarchitect.jpa.controllers;

import java.util.List;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.transaction.UserTransaction;
import shmallarchitect.jpa.controllers.exceptions.NonexistentEntityException;
import shmallarchitect.jpa.controllers.exceptions.RollbackFailureException;
import shmallarchitect.jpa.entities.Card;
import shmallarchitect.jpa.entities.Gallery;
import shmallarchitect.jpa.entities.Locum;
import shmallarchitect.jpa.entities.Owner;
import shmallarchitect.jpa.entities.Field;
import java.util.HashSet;
import java.util.Set;
import shmallarchitect.jpa.entities.Category;

/**
 *
 * @author jaccus
 */
public class LocumJpaController {
    @Resource(mappedName="utx")
    private UserTransaction utx = null;
    @PersistenceUnit(unitName = "ShmallArchitectPU")
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Locum locum) throws RollbackFailureException, Exception {
        if (locum.getFields() == null) {
            locum.setFields(new HashSet<Field>());
        }
        if (locum.getCategories() == null) {
            locum.setCategories(new HashSet<Category>());
        }
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            Card card = locum.getCard();
            if (card != null) {
                card = em.getReference(card.getClass(), card.getId());
                locum.setCard(card);
            }
            Gallery gallery = locum.getGallery();
            if (gallery != null) {
                gallery = em.getReference(gallery.getClass(), gallery.getId());
                locum.setGallery(gallery);
            }
            Owner owner = locum.getOwner();
            if (owner != null) {
                owner = em.getReference(owner.getClass(), owner.getId());
                locum.setOwner(owner);
            }
            Set<Field> attachedFields = new HashSet<Field>();
            for (Field fieldsFieldToAttach : locum.getFields()) {
                fieldsFieldToAttach = em.getReference(fieldsFieldToAttach.getClass(), fieldsFieldToAttach.getId());
                attachedFields.add(fieldsFieldToAttach);
            }
            locum.setFields(attachedFields);
            Set<Category> attachedCategories = new HashSet<Category>();
            for (Category categoriesCategoryToAttach : locum.getCategories()) {
                categoriesCategoryToAttach = em.getReference(categoriesCategoryToAttach.getClass(), categoriesCategoryToAttach.getId());
                attachedCategories.add(categoriesCategoryToAttach);
            }
            locum.setCategories(attachedCategories);
            em.persist(locum);
            if (card != null) {
                card.getLocums().add(locum);
                card = em.merge(card);
            }
            if (gallery != null) {
                gallery.getLocums().add(locum);
                gallery = em.merge(gallery);
            }
            if (owner != null) {
                owner.getLocums().add(locum);
                owner = em.merge(owner);
            }
            for (Field fieldsField : locum.getFields()) {
                Locum oldLocumOfFieldsField = fieldsField.getLocum();
                fieldsField.setLocum(locum);
                fieldsField = em.merge(fieldsField);
                if (oldLocumOfFieldsField != null) {
                    oldLocumOfFieldsField.getFields().remove(fieldsField);
                    oldLocumOfFieldsField = em.merge(oldLocumOfFieldsField);
                }
            }
            for (Category categoriesCategory : locum.getCategories()) {
                categoriesCategory.getLocums().add(locum);
                categoriesCategory = em.merge(categoriesCategory);
            }
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Locum locum) throws NonexistentEntityException, RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            Locum persistentLocum = em.find(Locum.class, locum.getId());
            Card cardOld = persistentLocum.getCard();
            Card cardNew = locum.getCard();
            Gallery galleryOld = persistentLocum.getGallery();
            Gallery galleryNew = locum.getGallery();
            Owner ownerOld = persistentLocum.getOwner();
            Owner ownerNew = locum.getOwner();
            Set<Field> fieldsOld = persistentLocum.getFields();
            Set<Field> fieldsNew = locum.getFields();
            Set<Category> categoriesOld = persistentLocum.getCategories();
            Set<Category> categoriesNew = locum.getCategories();
            if (cardNew != null) {
                cardNew = em.getReference(cardNew.getClass(), cardNew.getId());
                locum.setCard(cardNew);
            }
            if (galleryNew != null) {
                galleryNew = em.getReference(galleryNew.getClass(), galleryNew.getId());
                locum.setGallery(galleryNew);
            }
            if (ownerNew != null) {
                ownerNew = em.getReference(ownerNew.getClass(), ownerNew.getId());
                locum.setOwner(ownerNew);
            }
            Set<Field> attachedFieldsNew = new HashSet<Field>();
            for (Field fieldsNewFieldToAttach : fieldsNew) {
                fieldsNewFieldToAttach = em.getReference(fieldsNewFieldToAttach.getClass(), fieldsNewFieldToAttach.getId());
                attachedFieldsNew.add(fieldsNewFieldToAttach);
            }
            fieldsNew = attachedFieldsNew;
            locum.setFields(fieldsNew);
            Set<Category> attachedCategoriesNew = new HashSet<Category>();
            for (Category categoriesNewCategoryToAttach : categoriesNew) {
                categoriesNewCategoryToAttach = em.getReference(categoriesNewCategoryToAttach.getClass(), categoriesNewCategoryToAttach.getId());
                attachedCategoriesNew.add(categoriesNewCategoryToAttach);
            }
            categoriesNew = attachedCategoriesNew;
            locum.setCategories(categoriesNew);
            locum = em.merge(locum);
            if (cardOld != null && !cardOld.equals(cardNew)) {
                cardOld.getLocums().remove(locum);
                cardOld = em.merge(cardOld);
            }
            if (cardNew != null && !cardNew.equals(cardOld)) {
                cardNew.getLocums().add(locum);
                cardNew = em.merge(cardNew);
            }
            if (galleryOld != null && !galleryOld.equals(galleryNew)) {
                galleryOld.getLocums().remove(locum);
                galleryOld = em.merge(galleryOld);
            }
            if (galleryNew != null && !galleryNew.equals(galleryOld)) {
                galleryNew.getLocums().add(locum);
                galleryNew = em.merge(galleryNew);
            }
            if (ownerOld != null && !ownerOld.equals(ownerNew)) {
                ownerOld.getLocums().remove(locum);
                ownerOld = em.merge(ownerOld);
            }
            if (ownerNew != null && !ownerNew.equals(ownerOld)) {
                ownerNew.getLocums().add(locum);
                ownerNew = em.merge(ownerNew);
            }
            for (Field fieldsOldField : fieldsOld) {
                if (!fieldsNew.contains(fieldsOldField)) {
                    fieldsOldField.setLocum(null);
                    fieldsOldField = em.merge(fieldsOldField);
                }
            }
            for (Field fieldsNewField : fieldsNew) {
                if (!fieldsOld.contains(fieldsNewField)) {
                    Locum oldLocumOfFieldsNewField = fieldsNewField.getLocum();
                    fieldsNewField.setLocum(locum);
                    fieldsNewField = em.merge(fieldsNewField);
                    if (oldLocumOfFieldsNewField != null && !oldLocumOfFieldsNewField.equals(locum)) {
                        oldLocumOfFieldsNewField.getFields().remove(fieldsNewField);
                        oldLocumOfFieldsNewField = em.merge(oldLocumOfFieldsNewField);
                    }
                }
            }
            for (Category categoriesOldCategory : categoriesOld) {
                if (!categoriesNew.contains(categoriesOldCategory)) {
                    categoriesOldCategory.getLocums().remove(locum);
                    categoriesOldCategory = em.merge(categoriesOldCategory);
                }
            }
            for (Category categoriesNewCategory : categoriesNew) {
                if (!categoriesOld.contains(categoriesNewCategory)) {
                    categoriesNewCategory.getLocums().add(locum);
                    categoriesNewCategory = em.merge(categoriesNewCategory);
                }
            }
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Long id = locum.getId();
                if (findLocum(id) == null) {
                    throw new NonexistentEntityException("The locum with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Long id) throws NonexistentEntityException, RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            Locum locum;
            try {
                locum = em.getReference(Locum.class, id);
                locum.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The locum with id " + id + " no longer exists.", enfe);
            }
            Card card = locum.getCard();
            if (card != null) {
                card.getLocums().remove(locum);
                card = em.merge(card);
            }
            Gallery gallery = locum.getGallery();
            if (gallery != null) {
                gallery.getLocums().remove(locum);
                gallery = em.merge(gallery);
            }
            Owner owner = locum.getOwner();
            if (owner != null) {
                owner.getLocums().remove(locum);
                owner = em.merge(owner);
            }
            Set<Field> fields = locum.getFields();
            for (Field fieldsField : fields) {
                fieldsField.setLocum(null);
                fieldsField = em.merge(fieldsField);
            }
            Set<Category> categories = locum.getCategories();
            for (Category categoriesCategory : categories) {
                categoriesCategory.getLocums().remove(locum);
                categoriesCategory = em.merge(categoriesCategory);
            }
            em.remove(locum);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Locum> findLocumEntities() {
        return findLocumEntities(true, -1, -1);
    }

    public List<Locum> findLocumEntities(int maxResults, int firstResult) {
        return findLocumEntities(false, maxResults, firstResult);
    }

    private List<Locum> findLocumEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Locum as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Locum findLocum(Long id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Locum.class, id);
        } finally {
            em.close();
        }
    }

    public int getLocumCount() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Locum as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
